package git.bankview.sl.util;

import git.bankview.sl.Globals;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.text.ParseException;
import java.lang.reflect.*;
import org.apache.log4j.Logger;

public class LangUtil
{
	private static Logger log = Logger.getLogger(LangUtil.class);

	private static SimpleDateFormat m_oDatetimeFormat = new SimpleDateFormat(Globals.FORMAT_DATETIME);
	private static SimpleDateFormat m_oDateFormat = new SimpleDateFormat(Globals.FORMAT_DATE);
	private static SimpleDateFormat m_oTimeFormat = new SimpleDateFormat(Globals.FORMAT_TIME);
	
	public static Object safeCast(Class toClass, Object obj)
	{
		if (null != obj && !toClass.isInstance(obj))
		{
			Class fromClass = obj.getClass();
			if (Boolean.class.equals(toClass))
			{
				obj = Boolean.valueOf(obj.toString());
			}
			else if (java.util.Date.class.equals(toClass))
			{
				String str = obj.toString();
				obj = parseDatetime(str, m_oDatetimeFormat);
				if (null == obj)
					obj = parseDatetime(str, m_oDateFormat);
				if (null == obj)
					obj = parseDatetime(str, m_oTimeFormat);
			}
			else if (java.sql.Date.class.equals(toClass))
			{
				String str = obj.toString();
				obj = parseDatetime(str, m_oDateFormat);
				if (null != obj)
					obj = new java.sql.Date(((java.util.Date)obj).getTime());
			}
			else if (java.sql.Time.class.equals(toClass))
			{
				String str = obj.toString();
				obj = parseDatetime(str, m_oTimeFormat);
				if (null != obj)
					obj = new java.sql.Time(((java.util.Date)obj).getTime());
			}
			else if (java.sql.Timestamp.class.equals(toClass))
			{
				String str = obj.toString();
				obj = parseDatetime(str, m_oDatetimeFormat);
				if (null == obj)
					obj = parseDatetime(str, m_oDateFormat);
				if (null == obj)
					obj = parseDatetime(str, m_oTimeFormat);
				if (null != obj)
					obj = new java.sql.Timestamp(((java.util.Date)obj).getTime());
			}
			else if (java.lang.String.class.equals(toClass) && (obj instanceof java.util.Date))
			{
				if (java.sql.Date.class.equals(fromClass))
					obj = m_oDateFormat.format((java.util.Date)obj);
				else if (java.sql.Time.class.equals(fromClass))
					obj = m_oTimeFormat.format((java.util.Date)obj);
				else
					obj = m_oDatetimeFormat.format((java.util.Date)obj);
			}
			else // for other type
			{
				// try Constructor(prototype)
				Object toObj = newInstanceViaConstructor(toClass, fromClass, obj);
				if (null == toObj)
				{
					// try valueOf(prototype)
					toObj = newInstanceViaStaticMethod(toClass, "valueOf", fromClass, obj);
					
					if (null == toObj && !(obj instanceof String))
					{
						// try Constructor(String)
						toObj = newInstanceViaConstructor(toClass, String.class, obj.toString());
						
						if (null == toObj)
							toObj = newInstanceViaStaticMethod(toClass, "valueOf", String.class, obj.toString());
					}
				}
				
				obj = toObj;
			}
			
			if (null == obj)
			{
				throw new ClassCastException("can not cast " + obj + " to " + toClass);
			}
		}
		
		return obj;
	}
	
	private static java.util.Date parseDatetime(String str, DateFormat df)
	{
		try
		{
			return df.parse(str);
		}
		catch(ParseException e)
		{
			log.debug("parseDatetime()", e);
		}
		
		return null;
	}
	
	private static Object newInstanceViaConstructor(Class t, Class pType, Object obj)
	{
		try
		{
			Constructor c = t.getConstructor(new Class[] {pType});
			if (null != c)
				return c.newInstance(new Object[] {obj});
		}
		catch(Exception e)
		{
			log.debug("newInstanceViaConstructor()", e);
		}
		
		return null;
	}
	
	private static Object newInstanceViaStaticMethod(Class t, String methodName, Class pType, Object obj)
	{
		try
		{
			Method m = t.getMethod(methodName, new Class[] {pType});
			return m.invoke(null, new Object[] {obj});
		}
		catch(Exception e)
		{
			log.debug("newInstanceViaMethod()", e);
		}
		
		return null;
	}
}
